 
(function($){
	$.fn.formPartsOrderer = function(options) {

		// Options par defaut
		var defaults = {
		};
				
		var options = $.extend(defaults, options);
		
		var prefix = '' ;
		if(options.prefix != null) prefix = options.prefix + '_' ;
		
		function updateOrder(obj){
			// Pour chaque item de liste
			obj.find("li").each(function(){
				// On actualise sa position
				index = parseInt($(this).index()+1);
				// On la met à jour dans la page
				$(this).find(".count").text(index);
				$(this).find(".item").find(".order").val(index);
				
				var id = $(this).find(".item").find(".id").val() ;
				addDeleteTag($(this), id);
				deleteId(id);
			});
		}
		
		var ids = new Array() ;
		
		function isIdPresent(id){
			var value = false ;
			for(var i=0; i<ids.length; i++){
				if(ids[i] == id){
					value = true ;
					break;
				}
			}
			return value ;
		}
		
		function deleteId(id){
			for(var i=0; i<ids.length; i++){
				if(ids[i] == id){
					ids.splice(i, 1) ;
					return;
				}
			}
		}
		
		function addDeleteTag(elt, id){
			if(isIdPresent(id)){
				elt.parent().parent().append('<input type="hidden" name="'+prefix+'delete[]" value="'+id+'" />') ;
			}
		}
		
		this.each(function(){
				
			var obj = $(this);
			
			// Empêcher la sélection des éléments à la souris (meilleure gestion du drag & drop)
			var _preventDefault = function(evt) { evt.preventDefault(); };
			$("li").bind("dragstart", _preventDefault).bind("selectstart", _preventDefault);

			// Initialisation du composant "sortable"
			$(obj).sortable({
				axis: "y", // Le sortable ne s'applique que sur l'axe vertical
				containment: options.container, // Le drag ne peut sortir de l'élément qui contient la liste
				handle: ".item", // Le drag ne peut se faire que sur l'élément .item (le texte)
				distance: 5, // Le drag ne commence qu'à partir de 10px de distance de l'élément
				// Evenement appelé lorsque l'élément est relaché
				stop: function(event, ui){
					updateOrder(obj) ;
				}
			});
			
			// On ajoute un petit formulaire pour ajouter des items
			$(obj).after("<div class='add'>Ajouter <input class='addValue' type='text' /><input class='addId' type='hidden' /></div>");
			
			$(obj).parent().find(".addValue").autocomplete({
				source: options.serviceUrl,
				select: function(event, ui) {
					$(this).val(ui.item.label) ;
					$(this).parent().find(".addId").val(ui.item.id) ;
					addPart(this);
				},
				close: function(event, ui) {
					$(this).val("");
					$(this).parent().find(".addId").val("");
				}
			});
			
			// Pour chaque élément trouvé dans la liste de départ
			$(obj).find("li").each(function(){
				// On ajoute les contrôles
				addControls($(this));
			});
			
			/*
			* Ajouter les controles sur le bouton "ajouter"
			*
			* @Return void
			*/
			
			function addPart(autoCompleteInput){
				
				var val = $(autoCompleteInput).val() ;
				var id = $(autoCompleteInput).parent().find(".addId").val() ;
				// Si le texte n'est pas vide
				if(val != "" && id != "")
				{
					
					if(!isIdPresent(id)){
						// On ajoute un nouvel item à notre liste
						var inner = '' ;
						inner += '<li>' ;
						inner += '<span class="item"> ' ;
						inner += val + ' - ' ;
						inner += '<input class="id" type="hidden" name="'+prefix+'part_id[]" value="'+id+'" />' ;
						
						if(options.fields!=null){
							for(var i=0; i<options.fields.length; i++){
								
								if(i>0) inner += ' - ' ;
								var field = options.fields[i] ;
								
								var fieldVal='';
								if(field.defaultValue !== undefined){
									fieldVal = field.defaultValue;
								}
								
								var fieldType = field.type ;
								if(fieldType=='text') inner += '<label>'+field.label+' : <input type="text" name="'+prefix+field.name+'[]" size="'+field.size+'" value="'+fieldVal+'" /></label>' ;
								else if(fieldType=='select') inner += '<label>'+field.label+' : <select name="'+prefix+field.name+'[]" ><option value=""></option></select></label>' ;
							}
						}
						inner += '<input class="order" type="hidden" name="'+prefix+'part_order[]" value="" />' ;
						inner += '</span>' ;
						inner += '</li>' ;
						$(obj).append(inner) ;
						
						// On réinitialise le champ de texte pour l'ajout
						$(autoCompleteInput).val('') ;
						$(autoCompleteInput).parent().find(".addId").val('') ;
						
						// On ajoute les contrôles à notre nouvel item
						addControls($(obj).find("li:last-child"));
					}else{
						alert("La valeur est déjà dans la liste !"); 
					}
				}
			}
						
			
			/*
			* Fonction qui ajoute les contrôles aux items
			* @Paramètres
			*  - elt: élément courant (liste courante)
			*
			* @Return void
			*/
			
			function addControls(elt)
			{
				var index = parseInt($(elt).index()+1) ;
				
				// On ajoute l'élément de position
				$(elt).prepend('<span class="count">'+index+'</span> ');
				// Puis l'élément d'action (élément acheté)
				$(elt).append(' <span class="delete">X</span>') ;
				
				//update the position hidden field
				$(elt).find(".item").find(".order").val(index);
				
				ids.push($(elt).find(".item").find(".id").val()) ;
				
				// Au clic sur la croix de suppression
				$(elt).find(".delete").click(function(){
					if (confirm("Supprimer ?")){
						var val = $(elt).find(".item").find(".id").val() ;
						addDeleteTag($(elt), val);
						elt.remove() ;
						deleteId(val) ;
						updateOrder(obj) ;
					}
				}) ;
			}
		});
		// On continue le chainage JQuery
		return this;
	};})(jQuery);